package com.omesoft.hksnore.util.snore;

import android.util.Log;

import java.util.List;

/**
 * Created by Omesoft on 2017/3/5.
 *
 * 鼾声算法
 */

public class SnoreAlgorithm {
    private double dbSumFor2min = 0;
    private int snoreCountFor2min = 0;

    int dbTimesScope = 0;// 连续多少数据以内
    int upTimesScope = 4;// 递增次数
    int downTimesScope = 3;// 递减次数

    int tSnoreMin = 600;// 鼾声时长最小值,毫秒数
    int tSnoreMax = 4000;// 鼾声时长最大值,毫秒数
    int tNoSnoreMin = 1400;// 鼾声时长最小值,毫秒数
    int tNoSnoreMax = 4000;// 鼾声时长最大值,毫秒数

    int snoreStartTime = 0;// 鼾声开始时刻
    int snoreStopTime = 0;// 鼾声结束时刻
    long snoreTime = 0;// 下次鼾声开始时刻
    long noSnoreTime = 0;// 下次鼾声开始时刻

    double snore = 50.0d;
    int snoreTimes = 0;
    // 计算波形
    double dbNew = 0, dbOld = 0;
    int dbTimes = 0;// 连续多少数据以内
    int upTimes = 0;// 递增次数
    int downTimes = 0;// 递减次数
    int waveTimes = 0;// 波形次数

    public SnoreAlgorithm() {

    }

    public void handleDataFor2min(List<Double> data, int t) {
        snoreTimes = 0;
        dbSumFor2min = 0;
        snoreCountFor2min = 0;
        for (double db : data) {
            dbSumFor2min += db;
            // if (db > snore)
            // snoreCountFor2min++;
            snoreTimes++;
            clacSnore(db, t);
        }
    }

    private void clacSnore(double db, int t) {
        if (!String.valueOf(db).contains("n")) {
            // 计算鼾声次数
            dbTimes++;
            dbSumFor2min += db;
            // 递增超过一定次才能数鼾声
            dbNew = db;
            Log.d("test", "幅度::" + (dbNew - dbOld));
            if (dbNew > dbOld) {
                if (Math.abs(dbNew - dbOld) > 2) {
                    upTimes++;
                    downTimes = 0;
                    Log.d("test", "方向::" + upTimes);
                } else {
                    downTimes++;
                    upTimes = 0;
                    Log.d("test", "方向::-" + downTimes);
                }
            } else {
                if (Math.abs(dbNew - dbOld) > 2) {
                    downTimes++;
                    upTimes = 0;
                    Log.d("test", "方向::-" + downTimes);
                } else {
                    upTimes++;
                    downTimes = 0;
                    Log.d("test", "方向::" + upTimes);
                }
            }
            Log.d("test", "upTimes::" + upTimes + "downTimes::" + downTimes);
            dbOld = dbNew;

            if (upTimes > upTimesScope) {// 递增超过4次才能数鼾声
                snoreStartTime = snoreTimes * t;
                // Log.d("test", "开始打呼::" + snoreStartTime);
                noSnoreTime = snoreStartTime - snoreStopTime;
                Log.d("test", "打呼间隔时长::" + snoreTime);
                if (noSnoreTime > tNoSnoreMin && snoreTime < tNoSnoreMax) {
                    Log.d("test", dbTimes + "::符合打呼间隔::" + noSnoreTime);
                } else {
                    Log.d("test", dbTimes + "::不符合打呼间隔::" + noSnoreTime);

                }
            }

            if (snoreStartTime > 0 && downTimes > downTimesScope) {// 递增超过4次才能数鼾声
                snoreStopTime = snoreTimes * t;
                // Log.d("test", "结束打呼::" + snoreStopTime);
                snoreTime = snoreStopTime - snoreStartTime;
                Log.d("test", "打呼时长::" + snoreTime);
                if (snoreTime > tSnoreMin && snoreTime < tSnoreMax && db > snore) {
                    Log.d("test", dbTimes + "::符合打呼::" + snoreTime);
                    snoreCountFor2min++;

                    dbTimes = 0;
                    upTimes = 0;
                    downTimes = 0;
                } else {
                    Log.d("test", "::不符合打呼" + snoreTime);
                }
                snoreStartTime = snoreTimes * t;
            }
        }
    }

    /**
     * 获取2分钟里打鼾的次数
     *
     * @return
     */
    public int getSnoreCountFor2min() {
        return snoreCountFor2min;
    }

    /**
     * 将2分钟一次的数据合并
     *
     * @param data
     * @return
     */
    public double getDecibelFor2min() {
        return dbSumFor2min;
    }

	/*------------以上针对实时监测时的数据处理-------------------*/

    /**
     * 合并后的数据的时间点
     */
    private String[] merged_recordDate;
    /**
     * 合并点数量，指共多少条2分钟数据合并在一起
     */
    private int mergedCount = 5;
    /**
     * 合并后的余数时间
     */
    private int mergedSurplus = 0;
    /**
     * 统计各合并点日期上的层次
     */
    private int[] SnoreBarChar;
    /**
     * 深睡时间
     */
    private int DeepTime = 0;
    /**
     * 清醒时间
     */
    private int WakeUpTime = 0;
    /**
     * 浅睡时间
     */
    private int ShallowTime = 0;

    /**
     * 处理数据<br>
     * 1、将2分钟的数据合并成10分钟一次<br>
     * 2、计算合并点的日期<br>
     * 3、计算数据的三条平均线得出层次
     *
     * @param data
     */
    public void handleData(List<SnoreEntity> data) {
        try {
            int dataSize = data.size();
            String[] recordDate = new String[dataSize];// 记录每条数据的日期
            double[] decibels = new double[dataSize];
            for (int i = 0; i < dataSize; i++) {
                SnoreEntity entity = data.get(i);
                recordDate[i] = entity.getRecordDate();
                decibels[i] = Double.parseDouble(entity.getDecibels());
            }

            // 根据数据量划分合并点数量
            if (dataSize > 120)
                mergedCount = 5;
            else if (dataSize > 60)
                mergedCount = 3;
            else
                mergedCount = 2;
            Log.v("SnoreAlgorithm", "handleData::mergedCount::" + mergedCount);

            // 计算合并后的数据条数
            int mergedSize = 0;
            if (dataSize % mergedCount == 0) {
                mergedSize = dataSize / mergedCount;
            } else {
                mergedSize = dataSize / mergedCount + 1;
                mergedSurplus = dataSize % mergedCount;
            }
            Log.v("SnoreAlgorithm", "handleData::mergedSize::" + mergedSize);
            Log.v("SnoreAlgorithm", "handleData::mergedSurplus::" + mergedSurplus);

            // 计算合并点日期和合并分贝数
            double[] merged_decibel = new double[mergedSize];// 合并的分贝总和
            merged_recordDate = new String[mergedSize];
            for (int i = 0; i < dataSize; i++) {
                merged_decibel[i / mergedCount] += decibels[i];
                if (i % mergedCount == mergedCount - 1) {
                    merged_recordDate[i / mergedCount] = recordDate[i];
                }
                Log.v("SnoreAlgorithm", "handleData::merged_decibel[" + i / mergedCount + "]::"
                        + merged_decibel[i / mergedCount]);
                Log.v("SnoreAlgorithm", "handleData::merged_recordDate[" + i / mergedCount + "]::"
                        + merged_recordDate[i / mergedCount]);
            }
            if (mergedSurplus > 0) {
                merged_recordDate[mergedSize - 1] = recordDate[dataSize - 1];
                merged_decibel[mergedSize - 1] = decibels[mergedSize - 1] / mergedSurplus * mergedCount;
            }

            double snoreLine = 0.0d;// 超过这个值表示吵闹
            double quietLine = 0.0d;// 低于这个值表示安静
            // 计算平均值
            if (mergedSize > 2) {
                double average = 0.0d;// 平均值
                double dbSum = 0.0d;
                for (double db : merged_decibel) {
                    dbSum += db;
                }
                average = dbSum / mergedSize;
                int average_size_small = 0, average_size_large = 0;
                double dbSum_small = 0, dbSum_large = 0;
                for (int i = 1; i < mergedSize - 1; i++) {
                    if (merged_decibel[i] > average) {
                        average_size_large++;
                        dbSum_large += merged_decibel[i];
                    } else {
                        average_size_small++;
                        dbSum_small += merged_decibel[i];
                    }
                }
                snoreLine = dbSum_large / average_size_large;
                quietLine = dbSum_small / average_size_small;
            }
            Log.v("SnoreAlgorithm", "handleData::snoreLine::" + snoreLine);
            Log.v("SnoreAlgorithm", "handleData::quietLine::" + quietLine);

            // 然后将合并数据分类，得出对应合并时间时的状态
            // 睡眠监测中 0代表深睡 1代表浅睡 2代表清醒
            // 这里用 0表示安静 1表示XX 2表示吵闹
            SnoreBarChar = new int[mergedSize];
            DeepTime = 0;
            WakeUpTime = 0;
            ShallowTime = 0;
            for (int i = 0; i < mergedSize; i++) {
                if (merged_decibel[i] <= quietLine) {
                    DeepTime++;
                    SnoreBarChar[i] = 0;
                } else if (merged_decibel[i] >= snoreLine) {
                    WakeUpTime++;
                    SnoreBarChar[i] = 2;
                } else {
                    ShallowTime++;
                    SnoreBarChar[i] = 1;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String[] getMergedRecordDate() {
        Log.v("SnoreAlgorithm", "merged_recordDate::" + merged_recordDate.toString());
        return merged_recordDate;
    }

    public int getMergedCount() {
        Log.v("SnoreAlgorithm", "mergedCount::" + mergedCount);
        return mergedCount;
    }

    public int getMergedSurplus() {
        Log.v("SnoreAlgorithm", "mergedSurplus::" + mergedSurplus);
        return mergedSurplus;
    }

    public int[] getSnoreBarChar() {
        Log.v("SnoreAlgorithm", "SnoreBarChar::" + SnoreBarChar);
        return SnoreBarChar;
    }

    /**
     * 返回深睡时间（已运算）
     *
     * @return
     */
    public int getDeepTime() {
        Log.v("SnoreAlgorithm", "DeepTime::" + DeepTime);
        return DeepTime * 2 * mergedCount;
    }

    /**
     * 返回清醒时间（已运算）
     *
     * @return
     */
    public int getWakeUpTime() {
        Log.v("SnoreAlgorithm", "WakeUpTime::" + WakeUpTime);
        return WakeUpTime * 2 * mergedCount;
    }

    /**
     * 返回潜睡时间（已运算）
     *
     * @return
     */
    public int getShallowTime() {
        Log.v("SnoreAlgorithm", "ShallowTime::" + ShallowTime);
        return ShallowTime * 2 * mergedCount;
    }


}
